/*
 * Copyright 2009 SHOP.COM
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.shop.opensocial.mediated.shindig.request;

import com.google.inject.Inject;
import org.apache.shindig.config.ContainerConfig;
import org.apache.shindig.gadgets.Gadget;
import org.apache.shindig.gadgets.GadgetContext;
import org.apache.shindig.gadgets.LockedDomainService;
import org.apache.shindig.gadgets.AuthType;
import org.apache.shindig.gadgets.variables.Substitutions;
import org.apache.shindig.gadgets.preload.PreloadedData;
import org.apache.shindig.gadgets.process.ProcessingException;
import org.apache.shindig.gadgets.process.Processor;
import org.apache.shindig.gadgets.render.HtmlRenderer;
import org.apache.shindig.gadgets.render.Renderer;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.LocaleSpec;
import org.apache.shindig.gadgets.spec.SpecParserException;
import org.apache.shindig.gadgets.spec.View;
import org.apache.shindig.gadgets.spec.PipelinedData;
import org.apache.shindig.common.uri.Uri;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.Map;

/**
 * @author Jordan Zimmerman
 */
public class WrappedRenderer extends Renderer
{
	@Inject
	public WrappedRenderer(Processor processor, HtmlRenderer renderer, ContainerConfig containerConfig, LockedDomainService lockedDomainService)
	{
		super(new WrappedProcessor(processor), renderer, containerConfig, lockedDomainService);
	}

	private static class WrappedView extends View
	{
		private WrappedView(View view, String applicationId) throws SpecParserException
		{
			super("", new ArrayList<Element>(), null);
			fView = view;
			fApplicationId = applicationId;
		}

		@Override
		public String getName()
		{
			return fView.getName();
		}

		@Override
		public ContentType getType()
		{
			return fView.getType();
		}

		@Override
		public String getRawType()
		{
			return fView.getRawType();
		}

		@Override
		public Uri getHref()
		{
			return fView.getHref();
		}

		@Override
		public boolean getQuirks()
		{
			return fView.getQuirks();
		}

		@Override
		public int getPreferredHeight()
		{
			return fView.getPreferredHeight();
		}

		@Override
		public int getPreferredWidth()
		{
			return fView.getPreferredWidth();
		}

		@Override
		public String getContent()
		{
			StringBuilder		str = new StringBuilder();
			str.append("\n");
			str.append("<script language=\"javascript\">\n");
			str.append("gadgets.rpc.setAuthToken(\"..\", window.location.hash.substring(1));\n");
			str.append("gadgets.rpc.setRelayUrl(\"..\", gadgets.util.getUrlParameters()[\"parent\"] + \"/gadgets/files/container/rpc_relay.html\");\n");
			str.append("window.name='").append(fApplicationId).append("';\n");
			str.append("</script>\n");
			str.append(fView.getContent());
			return str.toString();
		}

		@Override
		public void setHrefContent(String content)
		{
			fView.setHrefContent(content);
		}

		@Override
		public boolean needsUserPrefSubstitution()
		{
			return fView.needsUserPrefSubstitution();
		}

		@Override
		public AuthType getAuthType()
		{
			return fView.getAuthType();
		}

		@Override
		public boolean isSignOwner()
		{
			return fView.isSignOwner();
		}

		@Override
		public boolean isSignViewer()
		{
			return fView.isSignViewer();
		}

		@Override
		public Map<String, String> getAttributes()
		{
			return fView.getAttributes();
		}

		@Override
		public PipelinedData getPipelinedData()
		{
			return fView.getPipelinedData();
		}

		@Override
		public View substitute(Substitutions substituter)
		{
			return fView.substitute(substituter);
		}

		@Override
		public String toString()
		{
			return fView.toString();
		}

		private final View 		fView;
		private final String	fApplicationId;
	}

	private static class WrappedProcessor extends Processor
	{
		private WrappedProcessor(Processor processor)
		{
			super(null, null, null, null);
			fProcessor = processor;
		}

		@Override
		public Gadget process(GadgetContext context) throws ProcessingException
		{
			Gadget 		gadget = fProcessor.process(context);
			return new WrappedGadget(gadget);
		}

		private final Processor fProcessor;
	}

	private static class WrappedGadget extends Gadget
	{
		public WrappedGadget(Gadget gadget)
		{
			fGadget = gadget;
		}

		@Override
		public Gadget setContext(GadgetContext context)
		{
			return fGadget.setContext(context);
		}

		@Override
		public GadgetContext getContext()
		{
			return fGadget.getContext();
		}

		@Override
		public Gadget setSpec(GadgetSpec spec)
		{
			return fGadget.setSpec(spec);
		}

		@Override
		public GadgetSpec getSpec()
		{
			return fGadget.getSpec();
		}

		@Override
		public Gadget setPreloads(Collection<PreloadedData> preloads)
		{
			return fGadget.setPreloads(preloads);
		}

		@Override
		public Collection<PreloadedData> getPreloads()
		{
			return fGadget.getPreloads();
		}

		@Override
		public Gadget setCurrentView(View currentView)
		{
			return fGadget.setCurrentView(currentView);
		}

		@Override
		public View getCurrentView()
		{
			try
			{
				return new WrappedView(fGadget.getCurrentView(), fGadget.getContext().getToken().getAppId());
			}
			catch ( SpecParserException e )
			{
				throw new Error(e);		// will never get here -JZ
			}
		}

		@Override
		public LocaleSpec getLocale()
		{
			return fGadget.getLocale();
		}

		@Override
		public void addFeature(String name)
		{
			fGadget.addFeature(name);
		}

		@Override
		public void removeFeature(String name)
		{
			fGadget.removeFeature(name);
		}

		@Override
		public Set<String> getAddedFeatures()
		{
			return fGadget.getAddedFeatures();
		}

		@Override
		public Set<String> getRemovedFeatures()
		{
			return fGadget.getRemovedFeatures();
		}

		@Override
		public boolean sanitizeOutput()
		{
			return fGadget.sanitizeOutput();
		}

		private final Gadget fGadget;
	}
}
